package no.nordicsemi.android.dfuupdate.scanner;

import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import no.nordicsemi.android.dfuupdate.R;
import no.nordicsemi.android.support.v18.scanner.ScanResult;

/**
 * DeviceListAdapter class is list adapter for showing scanned Devices name, address and RSSI image based on RSSI values.
 */
class BtchDeviceListAdapter extends BaseAdapter {
    private static final int TYPE_TITLE = 0;
    private static final int TYPE_ITEM = 1;
    private static final int TYPE_EMPTY = 2;

    private final ArrayList<ExtendedBluetoothDevice> listBondedValues = new ArrayList<>();
    private final ArrayList<ExtendedBluetoothDevice> listValues = new ArrayList<>();
    private final ArrayList<ExtendedBluetoothDevice> prefilterListValues = new ArrayList<>();
    private final Map<String,Boolean> checkedMap = new HashMap<String, Boolean>();

    public void editMap(String key, Boolean value) {
        checkedMap.put(key,value);
    }

    public void mapRemove(String key) {
        checkedMap.remove(key);
    }
    public Boolean findMap(String key) {
        if(!checkedMap.containsKey(key))
            return false;
        else
            return checkedMap.get(key);
    }

    public int getMapCount() {
        return checkedMap.size();
    }

    public void clearMap() {
        checkedMap.clear();
    }

    public ArrayList<String> getSelectedDevices() {
        ArrayList<String> selectedMacs = new ArrayList<String>();
        Iterator iter = checkedMap.entrySet().iterator();
        while (iter.hasNext())
        {
            Map.Entry entry = (Map.Entry) iter.next();
            String key = String.valueOf(entry.getKey());
            selectedMacs.add(key);
        }
        return selectedMacs;
    }

    private int deviceCount = 0;

    BtchDeviceListAdapter() {
    }

    /**
     * Sets a list of bonded devices.
     * @param devices list of bonded devices.
     */
    void addBondedDevices(@NonNull final Set<BluetoothDevice> devices) {
        for (BluetoothDevice device : devices) {
            listBondedValues.add(new ExtendedBluetoothDevice(device));
        }
        notifyDataSetChanged();
    }

    public  ArrayList<ExtendedBluetoothDevice> getDevices() {
        return this.listValues;
    }

    /**
     * Updates the list of not bonded devices.
     * @param results list of results from the scanner
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    public void update(@NonNull final List<ScanResult> results) {
        for (final ScanResult result : results) {
            final ExtendedBluetoothDevice device = findDevice(result);
            if (device == null) {
                //ExtendedBluetoothDevice newDev = new ExtendedBluetoothDevice(result);
                //listValues.add(newDev);
                prefilterListValues.add(new ExtendedBluetoothDevice(result));
            } else {
                device.name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;
                device.rssi = result.getRssi();
            }
        }


        filtList(ScanBatchActivity.keyWord);
        //sortList();
        notifyDataSetChanged();
    }




    private ExtendedBluetoothDevice findDevice(@NonNull final ScanResult result) {
        for (final ExtendedBluetoothDevice device : listBondedValues)
            if (device.matches(result))
                return device;
        for (final ExtendedBluetoothDevice device : prefilterListValues)
            if (device.matches(result))
                return device;
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    void sortList() {
        listValues.sort(new Comparator<ExtendedBluetoothDevice>() {
            @Override
            public int compare(ExtendedBluetoothDevice o1, ExtendedBluetoothDevice o2) {
                if(o1.rssi < o2.rssi)
                    return 1;
                else if (o1.rssi == o2.rssi) {
                    String mac1 = o1.device.getAddress();
                    String mac2 = o2.device.getAddress();
                    for(int i = 0;  i < o1.device.getAddress().length(); i++) {
                        if(mac1.charAt(i) < mac2.charAt(i))
                            return -1;
                        else if (mac1.charAt(i) == mac2.charAt(i))
                            continue;
                        else
                            return 1;
                    }
                    return 0;
                }
                else
                    return -1;
            }
        });
    }

    public void clearDevices() {
        listValues.clear();
        checkedMap.clear();
        prefilterListValues.clear();
        notifyDataSetChanged();
    }

    public void clearLeftDevice() {
        prefilterListValues.clear();
    }

    @Override
    public int getCount() {
        final int bondedCount = listBondedValues.size() + 1; // 1 for the title
        final int availableCount = listValues.isEmpty() ? 2 : listValues.size() + 1; // 1 for title, 1 for empty text
        if (bondedCount == 1)
            return availableCount;
        return bondedCount + availableCount;
    }

    public int getItemCount() {
        return deviceCount;
    }

    @Override
    public Object getItem(final int position) {
        final int bondedCount = listBondedValues.size() + 1; // 1 for the title
        if (listBondedValues.isEmpty()) {
            if (position == 0)
                return R.string.scanner_subtitle_not_bonded;
            else
                return listValues.get(position - 1);
        } else {
            if (position == 0)
                return R.string.scanner_subtitle_bonded;
            if (position < bondedCount)
                return listBondedValues.get(position - 1);
            if (position == bondedCount)
                return R.string.scanner_subtitle_not_bonded;
            return listValues.get(position - bondedCount - 1);
        }
    }

    @Override
    public int getViewTypeCount() {
        return 3;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(final int position) {
        return getItemViewType(position) == TYPE_ITEM;
    }

    @Override
    public int getItemViewType(final int position) {
        if (position == 0)
            return TYPE_TITLE;

        if (!listBondedValues.isEmpty() && position == listBondedValues.size() + 1)
            return TYPE_TITLE;

        if (position == getCount() - 1 && listValues.isEmpty())
            return TYPE_EMPTY;

        return TYPE_ITEM;
    }

    @Override
    public long getItemId(final int position) {
        return position;
    }

    @Override
    public View getView(final int position, @Nullable final View oldView, @NonNull final ViewGroup parent) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final int type = getItemViewType(position);

        View view = oldView;
        switch (type) {
            case TYPE_EMPTY:
                if (view == null) {
                    view = inflater.inflate(R.layout.device_list_empty, parent, false);
                }
                break;
            case TYPE_TITLE:
                if (view == null) {
                    view = inflater.inflate(R.layout.device_list_title, parent, false);
                }
                final TextView title = (TextView) view;
                title.setText((Integer) getItem(position));
                break;
            default:
                if (view == null) {
                    view = inflater.inflate(R.layout.dev_lst_row_bat, parent, false);
                    final ViewHolder holder = new ViewHolder();
                    holder.name = view.findViewById(R.id.name);
                    holder.address = view.findViewById(R.id.address);
                    holder.rssi = view.findViewById(R.id.rssi_value);
                    holder.checkBox = view.findViewById(R.id.checkbox);
                    view.setTag(holder);
                }

                final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position);
                final ViewHolder holder = (ViewHolder) view.getTag();
                final String name = device.name;
                holder.name.setText(name != null ? name : parent.getContext().getString(R.string.not_available));
                holder.address.setText(device.device.getAddress());
                if(checkedMap.containsKey(device.device.getAddress())) {
                    holder.checkBox.setChecked(true);
                } else {
                    holder.checkBox.setChecked(false);
                }
                if (!device.isBonded || device.rssi != ExtendedBluetoothDevice.NO_RSSI) {
                    //final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f));
                    holder.rssi.setText(String.valueOf(device.rssi) + "dBm");
                    //holder.rssi.setImageLevel(rssiPercent);
                    holder.rssi.setVisibility(View.VISIBLE);
                } else {
                    holder.rssi.setVisibility(View.GONE);
                }
                break;
        }

        return view;
    }

    private class ViewHolder {
        private CheckBox checkBox;
        private TextView name;
        private TextView address;
        private TextView rssi;
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public void filtList(String keyword) {
        if(keyword == null) {
            Log.d("KEYWORD", "Is NULL");
            keyword = "";
        }
        else {
            Log.d("KEYWORD", keyword);
        }

        deviceCount = 0;
        //List<ExtendedBluetoothDevice> ret = new ArrayList<>();

        String[] arr = keyword.split(" ");
        listValues.clear();
        for(int i = 0; i < prefilterListValues.size(); i++) {
            ExtendedBluetoothDevice device = prefilterListValues.get(i);
            //listValues.clear();
            String name = (device.name == null) ? "N/A" : device.name.toUpperCase();
            String mac = device.device.getAddress();
            boolean isTarget = true;
            for(String key : arr) {
                if(!name.contains(key) && !mac.contains(key)) {
                    isTarget = false;
                    break;
                }
            }
            if(isTarget) {
                listValues.add(device);
                Log.d("DeviceList ADD", name + "::" + mac);
                deviceCount++;
            }
        }
        sortList();
        Log.d("SORTED", "True");

        notifyDataSetChanged();
        Log.d("Notified", "True");
    }


}
